/**************************************************************************//**
\file  tmp175.c

\brief This module provides access to tmp175 the sensor. \n
       Copied from lm73.c file included in MeshBean board.

\author
	   Ricardo Rodrigues
	   
\internal
  History:
    29/06/12 R. Rodrigues - Created
******************************************************************************/
/******************************************************************************
                   Includes section
******************************************************************************/
#include <tmp175.h>
#include <i2cPacket.h>
#include <appTimer.h>
#include <sensors.h>

/******************************************************************************
                   Define(s) section
******************************************************************************/
// device address on i2c bus
#define TMP175_DEVICE_ADDR  (0x92 >> 1)

// device registers internal address
#define TMP175_DATA_REGISTER 0x00
#define TMP175_CONFIGURATION_REGISTER 0x01
#define TMP175_LOWER_LIMIT_REGISTER 0x02
#define TMP175_UPPER_LIMIT_REGISTER 0x03

#define TMP175_CONFIG_SHUTDOWN		0xE1
#define TMP175_CONFIG_CONTINUOUS	0x60

#define TMP175_DELAY						250	// in milliseconds

#define TMP175_STATE_QUEUE_LEN				8	// state queue length

/******************************************************************************
                   Global variables section
******************************************************************************/
// The flow control variable
static Tmp175Control_t tmp175Control;

// hods a FIFO queue of task for the bspBMP085Handler task handler function
static Tmp175States_t tmp175State[TMP175_STATE_QUEUE_LEN] = { TMP175_IDLE };

// I2C access control variable
static HAL_I2cDescriptor_t i2cParam = 
{
	.tty = TWI_CHANNEL_0,
	.id = TMP175_DEVICE_ADDR,
	.clockRate = I2C_CLOCK_RATE_62
};
// Timer structure, used to make the delays needed for A2D conversion
static HAL_AppTimer_t tmp175Delay;

// Auxiliary variables
uint8_t ctrl_reg_data;
int16_t i;

/******************************************************************************
                   Implementations section
******************************************************************************/
/**************************************************************************//**
\brief  Adds a new task to the task queue, FIFO style.

\param[in]
  task - the task to be queued.

\return
  BC_FAIL - if the queue if full, has more than BMP085_STATE_QUEUE_LEN tasks
  BC_SUCCESS - other case.

******************************************************************************/
result_t tmp175PushTask(Tmp175States_t task)
{	
	uint8_t i;
	for( i=0; i < TMP175_STATE_QUEUE_LEN-1; i++)
	{
		/* the queue is filled with IDLE tasks by default.
		The first IDLE task found will be replaced by the task we want to add. */
		if( tmp175State[i] == TMP175_IDLE )
		{
			tmp175State[i] = task;
			return BC_SUCCESS;
		}
	}
	return BC_FAIL;
}

/**************************************************************************//**
\brief	Returns the first task to be executed from the queue, FIFO style.

\return
	the task in queue to be executed.
******************************************************************************/
Tmp175States_t tmp175PopTask(void)
{	
	uint8_t i;
	Tmp175States_t task = tmp175State[0];
	
	for( i=0; i < TMP175_STATE_QUEUE_LEN-1; i++)
	{
		tmp175State[i] = tmp175State[i+1];
	}
	return task;
}


/**************************************************************************//**
\brief  Initializes the sensor and starts reads the calibration values.

\param[in]
  bmp085Result - pointer to a variable holding the result BC_SUCCESS/FAIL of
				 the whole operation.
\param[in]
  bmp085Pressure - pointer to a variable that will hold the pressure value.

\return
  BC_FAIL - if the sensor was open and running other tasks.
  BC_SUCCESS - other case.

******************************************************************************/
result_t openTmp175(void)
{
	if (TMP175_IDLE == tmp175State[0])
		return BC_SUCCESS;
		
	return BC_FAIL;
}


/**************************************************************************//**
\brief  Performs the test if the component have completed request.

\return
  BC_FAIL - the previous request is not completed.
  BC_SUCCESS - otherwise.
******************************************************************************/
result_t closeTmp175(void)
{
  if (TMP175_IDLE == tmp175State[0])
    return BC_SUCCESS;

  return BC_FAIL;
}


/**************************************************************************//**
\brief Handles the I2C interrupts.

\param[in]
  result - the result of the operation true - successful, false - failed.
******************************************************************************/
void tmp175I2CHandler(bool result)
{
	// close resource
	HAL_CloseI2cPacket(&i2cParam);
	if (false == result)
	{
    	/* If failed, return BC_FAIL as result and call the upper task handler
	       with the return state in bmp085Control.bmp085Return assigned from
	       sensor.c file */
		tmp175Control.tmp175Callback(false, (int16_t)0x00);
	}
	else
	{
    	// If successful, return BC_SUCCESS and proceed to the next task
		tmp175Control.tmp175Result = true;
		bspPostTask(BSP_TEMPERATURE);
	}
}

/**************************************************************************//**
\brief Reads the temperature value.
******************************************************************************/
result_t readTmp175Data(void (*f)(bool result, int16_t data))
{	
	if (TMP175_IDLE != tmp175State[0])
		return BC_FAIL;

	if (!f)
		return BC_FAIL;
		
	tmp175Control.tmp175Callback = f;

	if (BC_FAIL == tmp175PushTask(TMP175_SET_CONFIG))
		return BC_FAIL;
	if (BC_FAIL == tmp175PushTask(TMP175_WAIT))
		return BC_FAIL;
	if (BC_FAIL == tmp175PushTask(TMP175_GET_TEMP))
		return BC_FAIL;
	if (BC_FAIL == tmp175PushTask(TMP175_FORMAT_TEMP))
		return BC_FAIL;
	if (BC_FAIL == tmp175PushTask(TMP175_RETURN))
		return BC_FAIL;
	bspPostTask(BSP_TEMPERATURE);
	
	return BC_SUCCESS;
}

/**************************************************************************//**
\brief BMP085 Task Handler.
******************************************************************************/
void bspTMP175Handler(void)
{
	Tmp175States_t task;
	task = tmp175PopTask();

	if (task ==	TMP175_IDLE)
	{	// IDLE state, does nothing
		return;
	}

	if (task ==	TMP175_RETURN)
	{	// if queue is empty, call top layer task handler, else continue to next task
		if (TMP175_IDLE == tmp175State[0])
			tmp175Control.tmp175Callback(tmp175Control.tmp175Result, tmp175Control.tmp175Data);
		else
			bspPostTask(BSP_TEMPERATURE);

		return;
	} // RETURN

	if (task ==	TMP175_WAIT)
	{	// wait TMP175_WAIT milliseconds to jump to the next task
		tmp175Delay.interval = TMP175_DELAY;					// Timer interval in milliseconds
		tmp175Delay.mode     = TIMER_ONE_SHOT_MODE;				// One shot mode (TIMER_REPEAT_MODE or TIMER_ONE_SHOT_MODE)
		tmp175Delay.callback = bspTMP175Handler;				// Callback function for timer fire event
		HAL_StartAppTimer(&tmp175Delay);
		return;
	} // WAIT

	if (task ==	TMP175_SET_CONFIG)
	{	// xxx
		if (-1 == HAL_OpenI2cPacket(&i2cParam))
		{
			tmp175I2CHandler(false);
			return;
		}			

		ctrl_reg_data = TMP175_CONFIG_SHUTDOWN;
		i2cParam.data = &ctrl_reg_data;
		i2cParam.length = HAL_ONE_BYTE_SIZE;						// read one bytes
		i2cParam.lengthAddr = HAL_ONE_BYTE_SIZE;					// address has one byte
		i2cParam.internalAddr = TMP175_CONFIGURATION_REGISTER;		
		i2cParam.f = tmp175I2CHandler;								
		
		if (-1 == HAL_WriteI2cPacket(&i2cParam))
			tmp175I2CHandler(false);

		return;
	} // TMP175_SET_CONFIG

	if (task ==	TMP175_GET_TEMP)
	{	// xxx
		if (-1 == HAL_OpenI2cPacket(&i2cParam))
		{
			tmp175I2CHandler(false);
			return;
		}			
  
		i2cParam.data = (uint8_t*)(&tmp175Control.tmp175Data);		// where to store the data
		i2cParam.length = 2;										// read 2 bytes
		i2cParam.lengthAddr = HAL_ONE_BYTE_SIZE;					// address has one byte
		i2cParam.internalAddr = TMP175_DATA_REGISTER;				// start reading from TMP175_DATA_REGISTER
		i2cParam.f = tmp175I2CHandler;								// when finished call bmp085I2CHandler
		
		if (-1 == HAL_ReadI2cPacket(&i2cParam))
			tmp175I2CHandler(false);

		return;
	} // TMP175_GET_TEMP

	if (task ==	TMP175_FORMAT_TEMP)
	{	// xxx
	    i = (uint8_t)tmp175Control.tmp175Data;
	    i <<= 8;
		i |= ((tmp175Control.tmp175Data >> 8) & 0xFF);
		tmp175Control.tmp175Data = (i >> 4);
		bspPostTask(BSP_TEMPERATURE);
	}		
}

// eof tmp175.c
